package velha.connection.bt;

import java.io.IOException;
import java.util.Vector;
import javax.bluetooth.*;
import javax.microedition.io.Connector;
import javax.microedition.io.StreamConnection;
import javax.microedition.lcdui.Alert;
import javax.microedition.lcdui.AlertType;
import velha.game.Constantes;
import velha.game.Player;
import velha.game.Rival;
import velha.game.VelhaCanvas;

public class BTCliente implements DiscoveryListener {

    public static final boolean DEBUG = false;
    //Desceve servidor velha
    private static final UUID VELHA_SERVIDOR_UUID = new UUID("F5B0D0E4B0A05A908070605040302010", false);
    //Engine pronta.
    private static final int PRONTO = 0;
    //engine buscando dispositivos
    private static final int BUSCANDO_DISPOSITIVOS = 1;
    //Engine buscando servicos
    private static final int BUSCANDO_SERVICOS = 2;
    //Gurada estado da engine
    private int state = PRONTO;
    //Guarda referencia do discovery agent.
    private DiscoveryAgent discoveryAgent;
    //Guarda referencia da GUI.
    private GUICliente parent;
    //Guarda dispositivos encontrados
    private Vector devices = new Vector();
    //Guarda servicos encontrados
    private Vector records = new Vector();
    //Guarda codigo retornado da busca de dispositivos.
    //private int discType;
    //Guarda ids das buscas de servicos ( Para poder cancelar ). 
    private int[] searchIDs;
    //Guarda padrao de busca de servicos.
    private UUID[] uuidSet;
    private boolean isClosed = false;
    private boolean conexaoCancelada;
    private LocalDevice localDevice;

    public BTCliente(GUICliente parent) {
        this.parent = parent;

        boolean isBTReady = false;

        try {
            // create/get a local device and discovery agent
            localDevice = LocalDevice.getLocalDevice();
            discoveryAgent = localDevice.getDiscoveryAgent();

            // remember we've reached this point.
            isBTReady = true;
        } catch (Exception e) {
        }

        parent.completeInitialization(isBTReady);

        // nothing to do if no bluetooth available
        if (!isBTReady) {
            return;
        }

        // initialize some optimization variables
        uuidSet = new UUID[2];

        // ok, we are interesting in btspp services only
        uuidSet[0] = new UUID(0x1101);

        // and only known ones, that allows pictures
        uuidSet[1] = VELHA_SERVIDOR_UUID;
    }

    private synchronized boolean buscaDispositivos() {
        // ok, start a new search then
        state = BUSCANDO_DISPOSITIVOS;
        devices.removeAllElements();

        try {
            discoveryAgent.startInquiry(DiscoveryAgent.GIAC, this);
        } catch (BluetoothStateException e) {
            parent.informSearchError("Problema ao iniciar busca");

            return true;
        }

        //Aguardar termino

        try {
            wait(); // until devices are found
        } catch (InterruptedException e) {

            return false;
        }

        // this "wake up" may be caused by 'destroy' call
        if (isClosed) {
            return false;
        }

        return true;
    }

    public synchronized boolean buscaServicos() {
        state = BUSCANDO_SERVICOS;
        records.removeAllElements();
        searchIDs = new int[devices.size()];

        boolean isSearchStarted = false;

        for (int i = 0; i < devices.size(); i++) {
            RemoteDevice rd = (RemoteDevice) devices.elementAt(i);

            try {
                searchIDs[i] = discoveryAgent.searchServices(null, uuidSet, rd, this);
            } catch (BluetoothStateException e) {
                searchIDs[i] = -1;

                continue;
            }

            isSearchStarted = true;
        }

        // at least one of the services search should be found
        if (!isSearchStarted) {
            parent.informSearchError("Falha ao buscar jogos.");

            return true;
        }

        //Aguradar termino da busca
        try {
            wait(); // until services are found
        } catch (InterruptedException e) {

            return false;
        }

        // this "wake up" may be caused by 'destroy' call
        if (isClosed) {
            return false;
        }

        // actually, no services were found
        if (records.isEmpty()) {
            parent.informSearchError("Nenhum jogo encontrado");
        }

        return true;
    }

    public void iniciaBusca() {
        Runnable busca = new Runnable() {

            public void run() {
                if (!buscaDispositivos() || devices.isEmpty()) {
                    return;
                }

                // search for services now
                if (!buscaServicos() || records.isEmpty()) {
                    return;
                }

                parent.exibeJogos(records);
            }
        };

        new Thread(busca).start();
    }

    public void cancelaBusca() {
        synchronized (this) {
            if (state == BUSCANDO_DISPOSITIVOS) {
                discoveryAgent.cancelInquiry(this);
            } else if (state == BUSCANDO_SERVICOS) {
                for (int i = 0; i < searchIDs.length; i++) {
                    discoveryAgent.cancelServiceSearch(searchIDs[i]);
                }
            }
        }
    }

    public void conecta(final int indice) {

        if (indice < 0) {
            return;
        }
        new Thread(new Runnable() {

            public void run() {
                conexaoCancelada = false;

                try {
                    Thread.sleep(2000);
                } catch (InterruptedException ex) {
                    Alert alerta = new Alert("Erro", "Thread interrompida" + ex, null, AlertType.ERROR);
                    alerta.setTimeout(Alert.FOREVER);
                    parent.midlet.getDisplay().setCurrent(alerta);
                }

                if (conexaoCancelada) {
                    return;
                }

                ServiceRecord sr = (ServiceRecord) records.elementAt(indice);

                // RemoteDevice ele = sr.getHostDevice();

                String url = sr.getConnectionURL(ServiceRecord.NOAUTHENTICATE_NOENCRYPT, false);

                try {
                    StreamConnection conn = (StreamConnection) Connector.open(url);

                    Player jogador = new Player();
                    jogador.caracter = Constantes.CARACTER_PLAYER_2;
                    jogador.isPlayer1 = false;
                    jogador.isPrimeiro = false;
                    // jogador.nome = localDevice.getFriendlyName();
                    jogador.pontos = 0;

                    Rival rival = new Rival();
                    rival.caracter = Constantes.CARACTER_PLAYER_1;
                    rival.id = 1;
                    //rival.nome = ele.getFriendlyName(true);
                    rival.pontos = 0;

                    VelhaCanvas game = new VelhaCanvas(parent.midlet, jogador, rival);

                    game.in = conn.openDataInputStream();
                    game.out = conn.openDataOutputStream();

                    game.lapis.isVisivel = false;

                    parent.midlet.getDisplay().setCurrent(game);

                    game.startMessageProcessing();
                } catch (IOException ex) {
                    Alert alerta = new Alert("Erro", "Problema durante conexao: " + ex, null, AlertType.ERROR);
                    alerta.setTimeout(Alert.FOREVER);
                    parent.midlet.getDisplay().setCurrent(alerta);
                }
            }
        }).start();
    }

    public void cancelaConexao() {
        conexaoCancelada = true;
    }

    public void destroy() {
        synchronized (this) {
            isClosed = true;
            conexaoCancelada = true;
            notify();
        }
    }

    public void deviceDiscovered(RemoteDevice rd, DeviceClass dc) {
        if (DEBUG) {
            System.out.println("RemoteDevice: " + rd);
        }

        if (devices.indexOf(rd) == -1) {
            devices.addElement(rd);
        }
    }

    public void inquiryCompleted(int discType) {
        //this.discType = discType;

        synchronized (this) {
            notify();
        }
    }

    public void servicesDiscovered(int transID, ServiceRecord[] srs) {

        if (DEBUG) {
            System.out.println("Services Discovered");
        }

        for (int i = 0; i < srs.length; i++) {
            if (DEBUG) {
                System.out.println("Service Record: " + srs[i]);
            }
            records.addElement(srs[i]);
        }
    }

    public void serviceSearchCompleted(int transID, int respCode) {
        // Procurar indice do transID em searchIDs
        int index = -1;

        for (int i = 0; i < searchIDs.length; i++) {
            if (searchIDs[i] == transID) {
                index = i;

                break;
            }
        }

        // Erro transID nao consta
        if (index == -1) {
            System.out.println("Busca por serviço completado não foi feita");
        } else {
            //Encontrou -> muda o valor pra -1
            searchIDs[index] = -1;
        }

        // Verificar se existe algum sem ser -1 se sim retorna, se todos for -1 busca de servicos completas
        for (int i = 0; i < searchIDs.length; i++) {
            if (searchIDs[i] != -1) {
                return;
            }
        }

        //Todas as transaçoes completas
        synchronized (this) {
            notify();
        }
    }
}
